home *** CD-ROM | disk | FTP | other *** search
- unit uMsgView;
-
- {
- *******************************************************************************
- * Descriptions: Implementation for SMS Listing
- * $Source: /cvsroot/fma/fma/uMsgView.pas,v $
- * $Locker: $
- *
- * Todo:
- *
- * Change Log:
- * $Log: uMsgView.pas,v $
- * Revision 1.38.6.1 2005/01/25 16:03:09 z_stoichev
- * Merged with 2.1 Beta 1 bugfixes
- *
- * Revision 1.38 2004/07/14 09:35:40 z_stoichev
- * - Fixed Delete text messages (stay on phone issue).
- * - Fixed Clear message preview/image when deleted.
- *
- * Revision 1.37 2004/07/07 11:21:07 z_stoichev
- * Fixed delete multiple messages.
- *
- * Revision 1.36 2004/07/06 14:06:53 z_stoichev
- * - Added Personalization default contact image.
- *
- * Revision 1.35 2004/06/29 12:37:07 z_stoichev
- * New message window renamed
- *
- * Revision 1.34 2004/06/28 23:01:15 z_stoichev
- * Delete message bugfixes.
- *
- * Revision 1.33 2004/06/25 08:15:42 z_stoichev
- * No quotes in imported message PDUs.
- *
- * Revision 1.32 2004/06/24 09:28:03 z_stoichev
- * Fixed unknown sender name lookup.
- *
- * Revision 1.31 2004/06/24 09:08:29 z_stoichev
- * - Added Chat to Contact
- *
- * Revision 1.30 2004/06/23 13:53:03 z_stoichev
- * Added Chat support
- *
- * Revision 1.29 2004/06/22 14:38:55 z_stoichev
- * - Fixed Export file type filter misusage/order.
- * - Fixed Export messages UTF-8 and html encoding.
- *
- * Revision 1.28 2004/06/08 19:20:50 lordlarry
- * Memory Leak fixed
- *
- * Revision 1.27 2004/05/19 18:34:16 z_stoichev
- * Build 0.1.0.35c
- *
- * Revision 1.26 2004/03/14 18:49:29 z_stoichev
- * Mark message as read/unread access state.
- * Changed colors.
- *
- * Revision 1.25 2004/03/09 15:06:29 z_stoichev
- * Added Delete Text messages progress dialog.
- *
- * Revision 1.24 2004/01/30 16:41:12 z_stoichev
- * Fixed Send contacts from SIM to Phone AV error.
- * Added Progress dialog on Uploading contacts.
- * Added Fma windows update on SMS Delete/Upload.
- *
- * Revision 1.23 2004/01/28 17:39:53 z_stoichev
- * Popup menu rearranged.
- *
- * Revision 1.22 2004/01/23 08:33:18 z_stoichev
- * Fixed numbers only shown on startup.
- * Fixed upload to phone routines.
- *
- * Revision 1.21 2004/01/15 14:15:12 z_stoichev
- * GUI Changes.
- *
- * Revision 1.20 2004/01/13 12:28:06 z_stoichev
- * Added New menu icons.
- *
- * Revision 1.19 2004/01/12 15:36:33 z_stoichev
- * Fixed Export to CSV.
- * Added Import from CSV.
- *
- * Revision 1.18 2003/12/18 12:44:16 z_stoichev
- * Drafts folder doesn't have auto select as read feature.
- * Send Message icon set.
- *
- * Revision 1.17 2003/12/17 16:57:25 z_stoichev
- * Added Send Message from Drafts.
- * Fixed Mark as Unread enabled state.
- *
- * Revision 1.16 2003/12/16 17:40:44 z_stoichev
- * Ignore incorrect data (corruptedt pdu).
- *
- * Revision 1.15 2003/12/12 16:54:24 z_stoichev
- * Added view customization support.
- *
- * Revision 1.14 2003/12/09 12:05:25 z_stoichev
- * Build 0.10.28c + 29a changes without new WaitComplete unit.
- *
- * Revision 1.13 2003/12/04 16:33:33 z_stoichev
- * Fixed Message Perview disappear when too low.
- * Added Inbox new messages number into Explorer.
- * Added timestamp to outgoing/archive messages.
- * Added Action buttons into message preview.
- *
- * Revision 1.12 2003/12/01 12:02:26 z_stoichev
- * Hit Enter shows properties window.
- *
- * Revision 1.11 2003/11/28 09:38:07 z_stoichev
- * Merged with branch-release-1-1 (Fma 0.10.28c)
- *
- * Revision 1.10.2.7 2003/11/27 16:05:53 z_stoichev
- * Fixed delete archive connection request.
- *
- * Revision 1.10.2.6 2003/11/14 15:41:02 z_stoichev
- * Updates for patch 27d.
- *
- * Revision 1.10.2.5 2003/11/13 16:38:36 z_stoichev
- * Changed images.
- * Added personalization support (sender image).
- *
- * Revision 1.10.2.4 2003/11/12 16:31:02 z_stoichev
- * Add voice call to sender.
- *
- * Revision 1.10.2.3 2003/11/06 16:28:47 z_stoichev
- * Action update state changed.
- * Bugfixes.
- *
- * Revision 1.10.2.2 2003/10/28 12:57:06 z_stoichev
- * Fixed upload to phone popup menu.
- *
- * Revision 1.10.2.1 2003/10/27 07:22:54 z_stoichev
- * Build 0.1.0 RC1 Initial Checkin.
- *
- * Revision 1.10 2003/10/23 12:29:45 z_stoichev
- * Double-click opens SMS details view.
- * Popup menu recreated.
- * Font changed.
- *
- * Revision 1.9 2003/10/15 11:10:23 z_stoichev
- * Fixed bug 823902: Move SMS from Archive to Phone/SIM.
- *
- * Revision 1.8 2003/10/10 13:27:44 z_stoichev
- * Default message "No items to display..."
- *
- * Revision 1.7 2003/07/02 12:38:57 crino77
- * little modify on sort
- * export xml csv
- * full unicode support
- * added header in csv file
- *
- * Revision 1.6 2003/02/25 07:05:11 crino77
- * Added popup menu in MemoMsgBody
- * Changed font size in MemoMsgBody
- *
- * Revision 1.5 2003/02/14 11:44:18 crino77
- * Changed MEMO > RichEdit
- * Added support to decode EMS
- * Added ExportList for export in html
- * Added 'MemoMsgBody.clear' to remove the last msg viewed
- *
- * Revision 1.4 2003/01/30 04:15:57 warren00
- * Updated with header comments
- *
- *
- *******************************************************************************
- }
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- Menus, ImgList, VirtualTrees, ExtCtrls, StdCtrls, TntStdCtrls, ComCtrls,
- TntComCtrls, GR32_Image, Buttons, Placemnt, LMDControl, LMDBaseControl,
- LMDBaseGraphicControl, LMDGraphicControl, LMDFill;
-
- type
- TfrmMsgView = class(TFrame)
- Splitter2: TSplitter;
- ListMsg: TVirtualStringTree;
- ImageList: TImageList;
- pmListMsg: TPopupMenu;
- Reply1: TMenuItem;
- Forward1: TMenuItem;
- N6: TMenuItem;
- Archive1: TMenuItem;
- MovetoArchive1: TMenuItem;
- Delete1: TMenuItem;
- N15: TMenuItem;
- Detail1: TMenuItem;
- N1: TMenuItem;
- ExportselectedSMS1: TMenuItem;
- pmRich: TPopupMenu;
- Copy1: TMenuItem;
- SendTO: TMenuItem;
- SIM1: TMenuItem;
- Phone1: TMenuItem;
- StoreAsSent1: TMenuItem;
- StoreAsUnsent1: TMenuItem;
- StoreAsSent2: TMenuItem;
- StoreAsUnsent2: TMenuItem;
- N2: TMenuItem;
- NoItemsPanel: TPanel;
- Newmessage1: TMenuItem;
- contactcall1: TMenuItem;
- N5: TMenuItem;
- PreviewPanel: TPanel;
- MemoMsgBody: TTntRichEdit;
- Panel3: TPanel;
- Panel2: TPanel;
- SelImage: TImage32;
- Panel4: TPanel;
- SpeedButton1: TSpeedButton;
- addcontact1: TMenuItem;
- SpeedButton2: TSpeedButton;
- SpeedButton3: TSpeedButton;
- SpeedButton4: TSpeedButton;
- SpeedButton5: TSpeedButton;
- Bevel1: TBevel;
- Timer1: TTimer;
- MarkasRead1: TMenuItem;
- MarkasUnread1: TMenuItem;
- FormStorage1: TFormStorage;
- SendMessage1: TMenuItem;
- ImportTextMessages1: TMenuItem;
- OpenDialog1: TOpenDialog;
- Label1: TLabel;
- LMDFill2: TLMDFill;
- StoredReadItems1: TMenuItem;
- StoredUnreadItems1: TMenuItem;
- N4: TMenuItem;
- ChatContact1: TMenuItem;
- N7: TMenuItem;
- procedure ListMsgBeforeCellPaint(Sender: TBaseVirtualTree;
- TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
- CellRect: TRect);
- procedure ListMsgCompareNodes(Sender: TBaseVirtualTree; Node1,
- Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
- procedure ListMsgFocusChanged(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Column: TColumnIndex);
- procedure ListMsgGetImageIndex(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
- var Ghosted: Boolean; var ImageIndex: Integer);
- procedure ListMsgGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
- Column: TColumnIndex; TextType: TVSTTextType;
- var CellText: WideString);
- procedure ListMsgHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
- Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- procedure Detail1Click(Sender: TObject);
- procedure Copy1Click(Sender: TObject);
- procedure StoreAsSent1Click(Sender: TObject);
- procedure StoreAsUnsent1Click(Sender: TObject);
- procedure StoreAsSent2Click(Sender: TObject);
- procedure StoreAsUnsent2Click(Sender: TObject);
- procedure ListMsgAfterPaint(Sender: TBaseVirtualTree;
- TargetCanvas: TCanvas);
- procedure pmListMsgPopup(Sender: TObject);
- procedure btnDELClick(Sender: TObject);
- procedure SpeedButton1Click(Sender: TObject);
- procedure ListMsgKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- procedure Splitter2Moved(Sender: TObject);
- procedure ListMsgChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
- procedure Timer1Timer(Sender: TObject);
- procedure MarkasReadUnreadClick(Sender: TObject);
- procedure ListMsgDblClick(Sender: TObject);
- procedure SendMessage1Click(Sender: TObject);
- procedure ImportTextMessages1Click(Sender: TObject);
- procedure StoredReadItems1Click(Sender: TObject);
- procedure StoredUnreadItems1Click(Sender: TObject);
- private
- FCustomImage: Boolean;
- function FlattenText(str: WideString): WideString;
- procedure ShowDetail;
- procedure WriteSMS(Mem: String; State: Integer = -1);
- procedure Set_CustomImage(const Value: Boolean);
- public
- procedure RenderListView(const sl: TStrings);
- procedure ExportList(FileType:Integer; Filename: WideString);
- property IsCustomImage: Boolean read FCustomImage write Set_CustomImage;
- end;
-
- TLookUpNumberThread = class(TThread)
- private
- FListMsg: TVirtualStringTree;
- node: PVirtualNode;
- str: String;
- protected
- procedure Execute; override;
- procedure UpdateCaption;
- public
- constructor Create(ListMsg: TVirtualStringTree);
- end;
-
- TListData = Record
- imageindex: Integer;
- stateindex: Integer;
- from, msg: WideString;
- pdu: String;
- date: TDateTime;
- newmsg: Boolean;
- end;
- PListData = ^TListData;
-
- implementation
-
- {$R *.dfm}
-
- uses uMissedCalls, uSyncPhonebook, DateUtils, Unicode, Unit1, gsm_sms, uGlobal, uSMSDetail,
- uComposeSMS, uConnProgress, WebUtil;
-
- function TfrmMsgView.FlattenText(str: WideString): WideString;
- var
- sl: TWideStrings;
- i: Integer;
- begin
- sl := TWideStringList.Create;
- sl.Text := str;
-
- for i := 0 to sl.Count - 1 do begin
- Result := Result + WideChar(#32) + sl.Strings[i];
- end;
- sl.Destroy;
-
- Result := WideTrim(Result);
- end;
-
- procedure TfrmMsgView.ListMsgBeforeCellPaint(Sender: TBaseVirtualTree;
- TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
- CellRect: TRect);
- var
- item: PListData;
- begin
- item := Sender.GetNodeData(Node);
-
- if Node <> Sender.FocusedNode then begin
- if item.newmsg then begin
- TargetCanvas.Brush.Color := $00D0F8D0; // all columns (new msg)
- TargetCanvas.FillRect(CellRect);
- end
- else
- if Column = 0 then begin
- if item.imageindex = 17 then
- TargetCanvas.Brush.Color := $00E0E0FF // from column (out)
- else
- TargetCanvas.Brush.Color := $00FFE0E0; // from column (in)
- TargetCanvas.FillRect(CellRect);
- end;
- end;
- end;
-
- procedure TfrmMsgView.ListMsgCompareNodes(Sender: TBaseVirtualTree; Node1,
- Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
- var
- item1, item2: PListData;
- begin
- item1 := Sender.GetNodeData(Node1);
- item2 := Sender.GetNodeData(Node2);
-
- if Column = 0 then Result := CompareStr(item1.from, item2.from)
- else if Column = 1 then Result := WideCompareStr(item1.msg, item2.msg)
- else if Column = 2 then Result := CompareDateTime(item1.date, item2.date);
- end;
-
- procedure TfrmMsgView.ListMsgFocusChanged(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Column: TColumnIndex);
- const
- LastImage: string = '';
- var
- item: PListData;
- sms: TSMS;
- UDHI: String;
- pos, octet, {posTemp,} udhil: Integer;
- Description: String;
- contact: PContactData;
- s: WideString;
- begin
- IsCustomImage := False;
- if Node = nil then Exit;
-
- sms := TSMS.Create;//ADD
- try
- //posTemp := 0;
- item := Sender.GetNodeData(Node);
- MemoMsgBody.Text := item.msg;// + inttostr(length(item.msg));
- MemoMsgBody.DefAttributes.Color := clWindowText;
- MemoMsgBody.DefAttributes.Size := 10;
- sms.PDU := item.pdu; //ADD {
- { try to load contact personalized image and maintain a cache }
- s := Form1.LookupContact(sms.Number);
- if Form1.frmSyncPhonebook.FindContact(s,contact) then begin
- s := GetContactPictureFile(contact);
- if s <> '' then
- try
- { cache loaded image name }
- if not IsCustomImage or (s <> LastImage) then begin
- SelImage.Bitmap.LoadFromFile(s);
- IsCustomImage := True;
- LastImage := s;
- end;
- except
- IsCustomImage := False;
- end
- else
- IsCustomImage := False;
- end
- else
- IsCustomImage := False;
- { show message info }
- item.msg := sms.Text;
- if sms.IsUDH then begin
- UDHI := sms.UDHI;
- udhil := StrToInt('$' + copy(UDHI, 1, 2));
- //ANALIZE UDHI
- UDHI := Copy(UDHI, 3, length(UDHI));
- //pos := 1;
- repeat
- //Get the octet for type
- octet := StrToInt('$' + Copy(UDHI, 1, 2));
- UDHI := Copy(UDHI, 3, length(UDHI));
- case octet of
- 0:begin //SMS CONCATENATION
- pos := StrToInt('$' + Copy(UDHI, 1, 2)) + 1;
- Description := Description + '[SMS Concatenation';
- Description := Description + ' - SMS REF:' + IntToStr(StrToInt('$' + Copy(UDHI, 3, 2)));
- Description := Description + ' - SMS TOT:' + IntToStr(StrToInt('$' + Copy(UDHI, 5, 2)));
- Description := Description + ' - SMS N:' + IntToStr(StrToInt('$' + Copy(UDHI, 7, 2))) + ']';
- UDHI := Copy(UDHI, pos*2+1, length(UDHI));
- end;
- {10:begin //TEXT FORMATTING
- pos := StrToInt('$' + Copy(UDHI, 1, 2)) + 1 ;
- MemoMsgBody.SelStart := StrToInt('$' + Copy(UDHI, 3, 2));
- MemoMsgBody.SelLength := Length(MemoMsgBody.text) - MemoMsgBody.SelStart;
- UDHI := Copy(UDHI, pos*2+1, length(UDHI));
- Description := Description + '[EMS TEXT FORMATTING]';
- end;
- 11:begin //SOUND
- pos := StrToInt('$' + Copy(UDHI, 1, 2)) + 1;
- MemoMsgBody.SelStart := posTemp + StrToInt('$' + Copy(UDHI, 3, 2));
- MemoMsgBody.SelText := '[SOUND TYPE: ' + Copy(UDHI, 5, 2) + ']';
- posTemp := posTemp + 16 ;
- UDHI := Copy(UDHI, pos*2+1, length(UDHI));
- end;}
- else begin
- pos := udhil + 1;
- UDHI := Copy(UDHI, pos*2+1, length(UDHI));
- Description := '[EMS]';
- end
- end;
- until UDHI = '';
- MemoMsgBody.SelStart := length(MemoMsgBody.text);
- MemoMsgBody.selAttributes.Color := clGray;
- MemoMsgBody.selAttributes.Size := 8;
- MemoMsgBody.Lines.add(Description);
- end; //ADD }
- finally
- sms.Destroy; //ADD
- end;
- end;
-
- procedure TfrmMsgView.ListMsgGetImageIndex(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
- var Ghosted: Boolean; var ImageIndex: Integer);
- var
- item: PListData;
- begin
- if Column = 0 then begin
- if (Kind = ikNormal) or (Kind = ikSelected) then begin
- item := Sender.GetNodeData(Node);
- ImageIndex := item.imageindex;
- end
- else ImageIndex := -1;
- end;
- end;
-
- procedure TfrmMsgView.ListMsgGetText(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
- var CellText: WideString);
- var
- item: PListData;
- begin
- item := Sender.GetNodeData(Node);
-
- if Column = 0 then CellText := item.from
- else if Column = 1 then CellText := FlattenText(item.msg)
- else if Column = 2 then begin
- if item.date > 0 then begin
- if isToday(item.date) then CellText := TimeToStr(item.date)
- else CellText := DateTimeToStr(item.date)
- end
- else CellText := '';
- end;
- end;
-
- procedure TfrmMsgView.ListMsgHeaderClick(Sender: TVTHeader;
- Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
- Y: Integer);
- begin
- if Column = Sender.SortColumn then begin
- if Sender.SortDirection = sdDescending then
- Sender.SortDirection := sdAscending
- else
- Sender.SortDirection := sdDescending;
- end
- else
- Sender.SortColumn := Column;
- end;
-
- procedure TfrmMsgView.RenderListView(const sl: TStrings);
- var
- i: Integer;
- sms: TSMS;
- item: PListData;
- Node: PVirtualNode;
- dt: string;
- begin
- MemoMsgBody.Clear;//ADD
- FCustomImage := True; //Force image reload
- IsCustomImage := False;
- ListMsg.BeginUpdate;
- try
- ListMsg.Clear;
- ListMsg.NodeDataSize := sizeof(TListData);
-
- for i := 0 to sl.Count - 1 do begin
- Node := ListMsg.AddChild(nil);
- try
- item := ListMsg.GetNodeData(Node);
- item.pdu := GetToken(sl[i], 5);
-
- sms := Tsms.Create;
- try
- sms.PDU := item.pdu;
-
- item.from := sms.Number;
- item.date := sms.TimeStamp;
- item.msg := sms.Text;
-
- item.stateindex := StrToInt(GetToken(sl[i], 1)) and $FFFF; // index
-
- if StrToInt(GetToken(sl[i], 0)) = 1 then begin // ME
- item.ImageIndex := 14;
- item.StateIndex := item.StateIndex or $600000;
- end
- else if StrToInt(GetToken(sl[i], 0)) = 2 then begin // SM
- item.ImageIndex := 15;
- item.StateIndex := item.StateIndex or $640000;
- end
- else begin // PC
- if sms.IsOutgoing then item.ImageIndex := 17
- else item.ImageIndex := 16;
- item.StateIndex := item.StateIndex or $680000;
- end;
-
- // Direction Bit
- if sms.IsOutgoing then item.StateIndex := item.StateIndex or $020000
- else item.StateIndex := item.StateIndex or $010000;
-
- // New fields in 0.10.29a build
- try
- dt := GetToken(sl[i], 6);
- if dt <> '' then item.date := StrToDateTime(dt);
- item.newmsg := StrToInt(GetToken(sl[i], 7)) <> 0;
- except
- end;
- finally
- sms.Free;
- end;
- except
- ListMsg.DeleteNode(Node);
- Form1.Status('Error: Incorrect data ignored (Index: '+IntToStr(i)+', PDU: '+GetToken(sl[i], 5)+')');
- end;
- end;
- finally
- //ListMsg.Sort(nil, ListMsg.Header.SortColumn, ListMsg.Header.SortDirection);
- ListMsg.EndUpdate;
- if not Application.Terminated then
- TLookUpNumberThread.Create(ListMsg);
- end;
- end;
-
- {TLookUpNumberThread}
-
- constructor TLookUpNumberThread.Create(ListMsg: TVirtualStringTree);
- begin
- FListMsg := ListMsg;
- FreeOnTerminate := True;
- inherited Create(False);
- end;
-
- procedure TLookUpNumberThread.Execute;
- var
- sl: TStrings;
- item: PListData;
- begin
- { TODO -oLordLarry : This whole function is very thread UNSAFE }
- sl := TStringList.Create;
- try
- with FListMsg do begin
- node := GetFirst;
- if node <> nil then repeat
- try
- item := GetNodeData(node);
- item.from := Form1.ExtractNumber(item.from);
- str := sl.Values[item.from];
- if sl.IndexOfName(item.from) = -1 then begin
- str := Form1.LookupContact(item.from,sUnknownContact);
- sl.Add(item.from + '=' + str);
- end;
- if str <> '' then begin
- item.from := str + ' [' + item.from + ']';
- end;
- except
- end;
- node := GetNext(node);
- until Application.Terminated or (node = nil);
- end;
- if not Application.Terminated then
- Synchronize(UpdateCaption);
- finally
- sl.Destroy;
- end;
- end;
-
- procedure TLookUpNumberThread.UpdateCaption;
- begin
- if FListMsg <> nil then FListMsg.Repaint;
- end;
-
- procedure TfrmMsgView.ShowDetail;
- var
- node: PVirtualNode;
- item: PListData;
- begin
- node := ListMsg.FocusedNode;
- if node <> nil then begin
- item := ListMsg.GetNodeData(node);
- if item <> nil then begin
- if frmDetail = nil then
- frmDetail := TfrmDetail.Create(Self);
- frmDetail.PDU := item.pdu;
- frmDetail.Show;
- end;
- end;
- end;
-
- procedure TfrmMsgView.Detail1Click(Sender: TObject);
- begin
- Timer1.Enabled := False;
- Timer1.Interval := 100;
- Timer1.Enabled := (ListMsg.FocusedNode <> nil) and (Form1.Explorer.Selected <> Form1.FNodeMsgDrafts);
- ShowDetail;
- end;
-
- procedure TfrmMsgView.ExportList(FileType:Integer; Filename: WideString);
- var
- node: PVirtualNode;
- item: PListData;
- sl : TStringList;
- t,s,str : WideString;
- begin
- case FileType of
- 1:begin//CSV
- sl := TStringList.Create;
- str := '"Subject","Body","From: (Name)","From: (Address)","From: (Type)","To: (Name)","To: (Address)","To: (Type)",'+
- '"Fma Date","Fma State","Fma PDU","Fma IsNew"';
- sl.add(str);
- with ListMsg do begin
- node := GetFirst;
- repeat
- try
- if Selected[node] then begin
- item := GetNodeData(node);
- str := '"SMS","' + StringReplace(item.msg, '"', '""', [rfReplaceAll]) + '",';
- s := Form1.ExtractNumber(item.from);
- t := Form1.LookupContact(s,sUnknownContact) + ' [' + s + ']';
- if item.StateIndex and $020000 <> 0 then begin // outgoing message
- str := str + '"(Outgoing)","' + t + '","PHONE",';
- str := str + '"' + Form1.LookupContact(s) + '","' + s + '","PHONE",';
- end
- else begin
- str := str + '"' + Form1.LookupContact(s) + '","' + s + '","PHONE",';
- str := str + '"(Incoming)","' + t + '","PHONE",';
- end;
- if item.date > 0 then str := str + '"' + DateTimeToStr(item.date) + '",'
- else str := str + '"",';
- str := str + '"' + IntToStr(item.stateindex) + '","' + item.pdu + '","' + IntToStr(byte(item.newmsg)) + '"';
- sl.add(str);
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- end;
- sl.SaveToFile(FileName);
- sl.Destroy;
- end;
- 2:begin//XML
- sl := TStringList.Create;
- sl.Add('<?xml version="1.0" encoding="utf-8" ?>');
- sl.Add('<fma_messages>');
- with ListMsg do begin
- node := GetFirst;
- repeat
- try
- if Selected[node] then begin
- item := GetNodeData(node);
- str := '<sms>';
- str := str + '<from>' + HTMLEncode(UTF8Encode(item.from),False) + '</from>';
- str := str + '<msg>' + HTMLEncode(UTF8Encode(item.msg),False) + '</msg>';
- if item.date > 0 then
- str := str + '<date>' + HTMLEncode(UTF8Encode(DateTimeToStr(item.date)),False) + '</date>'
- else str := str + '<date/>';
- str := str + '</sms>';
- sl.add(str);
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- end;
- sl.Add('</fma_messages>');
- sl.SaveToFile(FileName);
- sl.Destroy;
- end;
- 3:begin//HTML
- sl := TStringList.Create;
- sl.Add('<html><head><meta content="text/html;charset=utf-8" http-equiv="content-type">');
- sl.Add('<title>FMA Messages</title></head><body>');
- sl.Add('<TABLE BORDER="1">');
- sl.Add('<TR><TD>FROM</TD><TD>BODY</TD><TD>DATE</TD></TR>');
- with ListMsg do begin
- node := GetFirst;
- repeat
- try
- if Selected[node] then begin
- item := GetNodeData(node);
- str := '<TR>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(item.from),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(item.msg),False) + '</TD>';
- if item.date > 0 then
- str := str + '<TD>' + HTMLEncode(UTF8Encode(DateTimeToStr(item.date)),False) + '</TD>'
- else str := str + '<TD></TD>';
- str := str + '</TR>';
- sl.add(str);
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- end;
- sl.Add('</TABLE>');
- sl.Add('</body></html>');
- sl.SaveToFile(FileName);
- sl.Destroy;
- end;
- end;
- end;
-
- procedure TfrmMsgView.Copy1Click(Sender: TObject);
- begin
- memomsgbody.CopyToClipboard;
- end;
-
- procedure TfrmMsgView.StoreAsUnsent1Click(Sender: TObject);
- begin
- WriteSMS('SM'); // default 0
- end;
-
- procedure TfrmMsgView.StoreAsSent1Click(Sender: TObject);
- begin
- WriteSMS('SM', 1);
- end;
-
- procedure TfrmMsgView.StoreAsUnsent2Click(Sender: TObject);
- begin
- WriteSMS('ME'); // default 0
- end;
-
- procedure TfrmMsgView.StoreAsSent2Click(Sender: TObject);
- begin
- WriteSMS('ME', 1);
- end;
-
- procedure TfrmMsgView.StoredUnreadItems1Click(Sender: TObject);
- begin
- WriteSMS('ME', 2);
- end;
-
- procedure TfrmMsgView.StoredReadItems1Click(Sender: TObject);
- begin
- WriteSMS('ME', 3);
- end;
-
- procedure TfrmMsgView.WriteSMS(Mem: String; State: Integer);
- var
- node,root,tmp: PVirtualNode;
- item: PListData;
- sms: Tsms;
- procedure DelNode;
- var
- i, index, location: Integer;
- begin
- index := item.StateIndex and $FFFF;
- location := ((item.StateIndex and $0C0000) shr 18) + 1;
-
- for i := 0 to TStrings(Form1.Explorer.Selected.Data).Count - 1 do begin
- if GetToken(TStrings(Form1.Explorer.Selected.Data).Strings[i], 1) = IntToStr(index) then begin
- if GetToken(TStrings(Form1.Explorer.Selected.Data).Strings[i], 0) = IntToStr(location) then begin
- TStrings(Form1.Explorer.Selected.Data).Delete(i);
- Form1.UpdateNewMessagesCounter(Form1.Explorer.Selected);
- break;
- end;
- end;
- end;
- ListMsg.DeleteNode(node);
- end;
- begin
- { State = -1 (default) means write as "received unread" }
- sms := Tsms.Create;
- ListMsg.BeginUpdate;
- try
- with ListMsg do begin
- node := GetFirst;
- root := node;
- repeat
- try
- if Selected[node] then begin
- item := GetNodeData(node);
- sms.PDU := item.pdu;
- if Form1.WriteSMS(Mem, item.pdu, State) then begin
- if node = root then begin
- DelNode;
- node := GetFirst;
- root := node;
- if root = nil then break;
- end
- else begin
- tmp := GetPrevious(node);
- DelNode;
- node := tmp;
- end;
- end;
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- end;
- finally
- ListMsg.EndUpdate;
- sms.Free;
- end;
- end;
-
- procedure TfrmMsgView.ListMsgAfterPaint(Sender: TBaseVirtualTree;
- TargetCanvas: TCanvas);
- begin
- NoItemsPanel.Visible := ListMsg.ChildCount[nil] = 0;
- end;
-
- procedure TfrmMsgView.pmListMsgPopup(Sender: TObject);
- var
- node: PVirtualNode;
- item: PListData;
- HasRead,HasUnread: boolean;
- begin
- HasRead := False;
- HasUnread := False;
- node := ListMsg.GetFirst;
- Repeat
- if ListMsg.Selected[node] then begin
- item := ListMsg.GetNodeData(node);
- if item.newmsg then HasUnread := True
- else HasRead := True;
- if HasRead and HasUnread then break;
- end;
- node := ListMsg.GetNext(node);
- Until node = nil;
- SendMessage1.Visible := Form1.Explorer.Selected = Form1.FNodeMsgDrafts;
- Newmessage1.Visible := not SendMessage1.Visible;
- Detail1.Enabled := ListMsg.SelectedCount = 1;
- SendMessage1.Enabled := Detail1.Enabled;
- MarkasRead1.Enabled := HasUnread;
- MarkasUnread1.Enabled := HasRead;
- SendTO.Enabled := Form1.Explorer.Selected = Form1.FNodeMsgArchive;
- SendTO.Visible := not SendMessage1.Visible;
- end;
-
- procedure TfrmMsgView.btnDELClick(Sender: TObject);
- var
- i, index: Integer;
- location: Integer;
- s,memType: String;
- node,prev: PVirtualNode;
- item: PListData;
- b: boolean;
- sl: TStrings;
- begin
- if ListMsg.SelectedCount = 0 then exit;
- s := 'Deleting ' + IntToStr(ListMsg.SelectedCount) + ' item(s)';
- b := Form1.skipDeleteWarn;
- Form1.skipDeleteWarn := False;
- if not b and (MessageDlg(s+'. Do you wish to continue?',mtConfirmation,[mbYes,mbNo],0) <> ID_YES) then
- exit;
- Form1.Status(s+'...');
- Update;
- frmConnect := GetProgressDialog;
- try
- if Form1.CanShowProgress then
- frmConnect.ShowProgress(Form1.FProgressLongOnly);
- frmConnect.Initialize(ListMsg.SelectedCount,s);
- ListMsg.Enabled := False; // prevent keyboard move up/down in list while deleteing
- ListMsg.BeginUpdate;
- try
- node := ListMsg.GetLast;
- while node <> nil do begin
- prev := nil;
- try
- if ListMsg.Selected[node] then begin
- item := ListMsg.GetNodeData(node);
- index := item.StateIndex and $FFFF;
- location := (item.StateIndex and $80000) shr 16;
-
- if location = 0 then // ME
- memType := 'ME'
- else
- if location = 4 then // SM
- memType := 'SM'
- else // 8, PC
- memType := '';
-
- { If deleteing from Outbox, notify and enable Chat window }
- if Form1.Explorer.Selected = Form1.FNodeMsgOutbox then
- Form1.ChatNotifyDel(item.pdu);
-
- { Remove message from database }
- sl := TStrings(Form1.Explorer.Selected.Data);
- for i := 0 to sl.Count - 1 do begin
- if WideCompareText(GetToken(sl[i], 5),item.pdu) = 0 then begin
- if memType <> '' then begin
- Form1.RequestConnection;
- Form1.DeleteSMS(index, memType);
- end;
- sl.Delete(i);
- prev := node;
- break;
- end;
- end;
-
- { Update progress }
- frmConnect.IncProgress(1);
- end;
- finally
- node := ListMsg.GetPrevious(node);
- { Remove already deleted message's node }
- if Assigned(prev) then begin
- { If deleteing current node, clear personalization and msg preview too }
- if prev = ListMsg.FocusedNode then begin
- MemoMsgBody.Clear;
- IsCustomImage := False;
- end;
- ListMsg.DeleteNode(prev);
- end;
- end;
- end;
- finally
- ListMsg.EndUpdate;
- ListMsg.Enabled := true;
- Form1.UpdateNewMessagesCounter(Form1.Explorer.Selected);
- end;
- finally
- FreeProgressDialog;
- end;
- Form1.Status('');
- end;
-
- procedure TfrmMsgView.SpeedButton1Click(Sender: TObject);
- begin
- Form1.ActionViewMsgPreview.Execute;
- end;
-
- procedure TfrmMsgView.ListMsgKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- begin
- if (Key = VK_RETURN) and (ListMsg.SelectedCount = 1) then
- Detail1Click(nil);
- end;
-
- procedure TfrmMsgView.Splitter2Moved(Sender: TObject);
- begin
- if PreviewPanel.Height < Splitter2.MinSize then PreviewPanel.Height := Splitter2.MinSize;
- end;
-
- procedure TfrmMsgView.ListMsgChange(Sender: TBaseVirtualTree;
- Node: PVirtualNode);
- begin
- Timer1.Enabled := False;
- Timer1.Interval := 4000;
- Timer1.Enabled := (ListMsg.SelectedCount = 1) and PreviewPanel.Visible and
- (Form1.Explorer.Selected <> Form1.FNodeMsgDrafts);
- end;
-
- procedure TfrmMsgView.Timer1Timer(Sender: TObject);
- var
- item: PListData;
- begin
- Timer1.Enabled := False;
- if ListMsg.FocusedNode = nil then exit;
-
- item := ListMsg.GetNodeData(ListMsg.FocusedNode);
- if item.newmsg then begin
- Form1.UpdateNewMessagesCounter(Form1.Explorer.Selected,item.pdu);
- item.newmsg := False;
- ListMsg.Update;
- end;
- end;
-
- procedure TfrmMsgView.MarkasReadUnreadClick(Sender: TObject);
- var
- node: PVirtualNode;
- item: PListData;
- AsRead: boolean;
- begin
- AsRead := TMenuItem(Sender).Tag <> 0;
- node := ListMsg.GetFirst;
- Repeat
- if ListMsg.Selected[node] then begin
- item := ListMsg.GetNodeData(node);
- if item.newmsg = AsRead then begin
- Form1.UpdateNewMessagesCounter(Form1.Explorer.Selected,item.pdu,AsRead);
- item.newmsg := not AsRead;
- end;
- end;
- node := ListMsg.GetNext(node);
- Until node = nil;
- ListMsg.Update;
- end;
-
- procedure TfrmMsgView.ListMsgDblClick(Sender: TObject);
- begin
- if Form1.Explorer.Selected = Form1.FNodeMsgDrafts then
- SendMessage1.Click
- else
- Detail1.Click;
- end;
-
- procedure TfrmMsgView.SendMessage1Click(Sender: TObject);
- var
- node: PVirtualNode;
- item: PListData;
- begin
- node := ListMsg.GetFirst;
- Repeat
- if ListMsg.Selected[node] then begin
- item := ListMsg.GetNodeData(node);
- Form1.ActionSMSNewMsg.Execute;
- frmMessageContact.AddRecipient(item.from);
- frmMessageContact.Memo.Text := item.msg;
- frmMessageContact.Memo.SelStart := Length(item.msg);
- end;
- node := ListMsg.GetNext(node);
- Until node = nil;
- ListMsg.Update;
- end;
-
- procedure TfrmMsgView.ImportTextMessages1Click(Sender: TObject);
- var
- ImpList: TStringList;
- sl: TStrings;
- t,str: WideString;
- i,j,Added,iBody,iDate,iState,iPDU,iNew: integer;
- function IsMultilineBody(s: WideString): boolean;
- var
- i,j: integer;
- begin
- j := 0;
- for i := 1 to length(s) do
- if s[i] = '"' then inc(j);
- Result := j mod 2 <> 0;
- end;
- begin
- if (Form1.Explorer.Selected = nil) or not OpenDialog1.Execute then exit;
- sl := TStrings(Form1.Explorer.Selected.Data);
- Added := 0;
- ImpList := TStringList.Create;
- try
- ImpList.LoadFromFile(OpenDialog1.FileName);
- if ImpList.Count <= 1 then raise Exception.Create('Nothing to import');
-
- Form1.Status('Importing messages...');
-
- iBody := 0; iDate := 0; iState := 0; iPDU := 0; iNew := 0;
- i := 0; str := '';
- while i < ImpList.Count do begin
- if Trim(ImpList[i]) <> '' then begin
- str := str + ImpList[i];
- if not IsMultilineBody(str) then begin
- if iBody = 0 then begin // find fields mapping
- for j := 0 to GetTokenCount(str)-1 do begin
- // "Subject","Body","From: (Name)","From: (Address)","From: (Type)","To: (Name)","To: (Address)","To: (Type)",
- // "Fma Date","Fma State","Fma PDU","Fma New"
- t := GetToken(str,j);
- if WideCompareText(t,'Body') = 0 then iBody := j;
- if WideCompareText(t,'Fma Date') = 0 then iDate := j;
- if WideCompareText(t,'Fma State') = 0 then iState := j;
- if WideCompareText(t,'Fma PDU') = 0 then iPDU := j;
- if WideCompareText(t,'Fma IsNew') = 0 then iNew := j;
- end;
- end
- else begin
- t := '3,' + IntToStr(sl.Count+1);
- if StrToInt(GetToken(str,iState)) and $2000 <> 0 then // outgoing message
- t := t + ',3,,,'
- else
- t := t + ',1,,,';
- t := t + '"' + GetToken(str,iPDU) + '","' + GetToken(str,iDate) + '",' + GetToken(str,iNew);
- { TODO: Avoid dublicated messages }
- sl.Add(t);
- inc(Added);
- end;
- str := '';
- end;
- end;
- inc(i);
- end;
- finally
- ImpList.Free;
- if Added <> 0 then begin
- Form1.UpdateNewMessagesCounter(Form1.Explorer.Selected);
- RenderListView(sl);
- Form1.Debug('Imported '+IntToStr(Added)+' item(s)...');
- end;
- end;
- Form1.Status('Import complete.');
- end;
-
- procedure TfrmMsgView.Set_CustomImage(const Value: Boolean);
- begin
- if not Value and (FCustomImage <> Value) then
- SelImage.Bitmap.Assign(Form1.CommonBitmaps.Bitmap[0]);
- FCustomImage := Value;
- end;
-
- end.
-
-